#include "EcrireXML.h"

#include "Qlib.h"

#include "ATL.h"

#include "Race.h"
#include "Classe.h"

#include "Joueur.h"

DebugLevelType EcrireXML::interne( BLANK );

/** Constructeur standard.
 * Le fichier est ouvert ici, et on termine la création de l'objet si
 * on ne peut pas l'écrire. On affecte la valeur "Joueur" à la balise
 * racine.
 *
 * @param[in] nom fichier à créer.
 * @param[in] j pointeur sur le Joueur à sauvegarder.
 * @param[in] xsd booléen servant à déterminer si on utilise la
 * validation par XSD (\e true) ou DTD (\e false).
 */
EcrireXML::EcrireXML(const std::string& nom, Joueur *j, const bool& xsd)
  : QObject(), ADDObjetBase( "EcrireXML" ), doc(), out(), UtiliseXSD( xsd )
{
  perso = j;
  racine = doc.createElement("Joueur");
  if ( UtiliseXSD )
    {
      racine.setAttribute( "xmlns:xsi",
			   "http://www.w3.org/2001/XMLSchema-instance" );
      racine.setAttribute( "xmlns", "http://www.w3schools.com" );
      racine.setAttribute( "xsi:schemaLocation",
			   "http://www.w3schools.com Joueur.xsd" );
    }
  doc.appendChild( racine );
  file.setFileName( nom.c_str() );
  /*
   * Ouverture du fichier de sauvegarde en ecriture
   */
  if ( ! file.open( QIODevice::WriteOnly ) )
    return;
  out.setDevice( &file ); //association du flux au fichier
}

/**
 * Destructeur, qui écrit la structure DOM remplie par ecrirePerso()
 * dans le fichier voulu. Le fichier contient un header avec la
 * version XML utilisée.
 */
EcrireXML::~EcrireXML()
{
  if ( ! UtiliseXSD )
    {
      QDomNode comm( doc.createComment( "DOCTYPE Joueur SYSTEM \"Joueur.dtd\"" ) );
      doc.insertBefore( comm, doc.firstChild() );
    }

  // Insertion en début de document de <?xml version="1.0"?>
  QDomNode noeud( doc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
  doc.insertBefore( noeud, doc.firstChild() );
  // Sauvegarde dans le flux (2 espaces de décalage dans l'arborescence)
  doc.save( out, 2 );
  file.close();
}

/**
 * Ecrit le Joueur dans le document. Le nombre de classe peut être
 * quelconque. Toutes les informations sont transformées en string
 * en interne et placées dans l'arbre DOM. Attention, le fichier
 * n'est pas écrit physiquement à ce point, c'est lors de la
 * destruction de l'objet que le ficher est écrit.
 *
 * Le niveau de sortie est paramétré par EcrireXML::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.\n
 * - \e LINFO affiche la chaîne de caractère associée à chaque balise.
 */
void EcrireXML::ecrirePerso()
{
  /*Debug::*/empileNiveau( &EcrireXML::interne );
  func() << "EcrireXML::ecrirePerso -> début" << endmsg;

  unsigned int taille, tabTraits[7];
  QString vecStr("");
  const vector< TypeClasse >   *vecAcces;
  const vector< Sort >         *vecSorts;
  const vector< unsigned int > *vecUint;

  /*
   * flot nous permet d'obtenir une string à partir de n'importe quoi.
   * ecrireUInt permet d'écrire un vecteur d'entier non signés.
   * ecrireTC permet d'écrire un vecteur de TypeClasse (sous forme
   * d'entiers).
   * ecrireSort permet d'écrire des sorts
   */
  stringstream flot;
  EcrireElementConteneur< unsigned int, ostream > ecrireUInt( &flot );
  EcrireElementConteneur< TypeClasse, ostream >   ecrireTC( &flot );
  EcrireElementConteneur< Sort, ostream >         ecrireSort( &flot );

  unsigned int i, NbrClasses( perso -> nbrClasses() );

  QDomElement nom( doc.createElement( "Nom" ) );
  racine.appendChild( nom );
  QDomText nomStr( doc.createTextNode( trUtf8( perso -> nom().c_str() ) ) );
  nom.appendChild( nomStr );
  linfo() << "Nom : " << toUtf8StdString( nomStr.data() ) << endmsg;

  QDomElement infoRace( doc.createElement( "Info_Raciales" ) );
  racine.appendChild( infoRace );

  QDomElement race( doc.createElement( "Race" ) );
  infoRace.appendChild( race );
  QDomText raceStr( doc.createTextNode( trUtf8(perso -> race().c_str() ) ) );
  race.appendChild( raceStr );
  linfo() << "Race : " << toUtf8StdString( raceStr.data() ) << endmsg;

  QDomElement capa( doc.createElement("Capacites" ) );
  infoRace.appendChild( capa );
  for_each( perso -> racePtr() -> adresseCapacites() -> begin(),
	    perso -> racePtr() -> adresseCapacites() -> end(),
	    ecrireUInt );
  QDomText capaStr( doc.createTextNode( trUtf8( flot.str().c_str() ) ) );
  capa.appendChild( capaStr );
  linfo() << "Capacités : " << toUtf8StdString( capaStr.data() ) << endmsg;

  QDomElement traits( doc.createElement( "Traits" ) );
  racine.appendChild( traits );
  perso -> traits( tabTraits );
  vecStr.clear();
  for (i = 0; i < 7; i++)
    {
      vecStr.append( QString::number( tabTraits[i] ) );
      vecStr.append( " " );
    }
  QDomText traitsStr( doc.createTextNode( vecStr ) );
  traits.appendChild( traitsStr );
  linfo() << "Traits : " << toUtf8StdString( traitsStr.data() ) << endmsg;

  QDomElement infoClasse( doc.createElement("Info_Classes") );
  racine.appendChild( infoClasse );

  QDomElement multi( doc.createElement("Multi") );
  infoClasse.appendChild( multi );
  QDomText multiStr( doc.createTextNode( QString::number(perso ->
							 nbrClasses() ) ) );
  multi.appendChild( multiStr );
  linfo() << "Nombre de classes : "
	  << toUtf8StdString( multiStr.data() ) << endmsg;

  QDomElement pp( doc.createElement( "PP" ) );
  infoClasse.appendChild( pp );
  QDomText ppStr( doc.createTextNode( QString::number(perso -> nbrPP() ) ) );
  pp.appendChild( ppStr );
  linfo() << "Nombre de pp : " << toUtf8StdString( ppStr.data() ) << endmsg;

  vector<QDomElement> infos;
  //vector<QDomText> infosStr;
  vector<QDomElement> classe;
  vector<QDomText> classeStr;
  vector<QDomElement> xp;
  vector<QDomText> xpStr;
  vector<QDomElement> comp;
  vector<QDomElement> pv;
  vector<QDomText> pvStr;
  vector<QDomText> compStr;
  vector<QDomElement> sorts;
  vector<QDomText> sortsStr;

  vecAcces = perso -> acces( taille );
  QDomElement acces( doc.createElement( "Acces" ) );
  infoClasse.appendChild( acces );
  vecStr.clear();
  flot.str("");
  
  for_each( vecAcces -> begin(), vecAcces -> end(), ecrireTC );
  // for (i = 0; i < taille; i++)
  //   {
  //     vecStr.append( QString::number(static_cast<unsigned int>((*vecAcces)[i])) );
  //     vecStr.append( " " );
  //   }
  QDomText accesStr( doc.createTextNode( trUtf8( flot.str().c_str() ) ) );
  acces.appendChild( accesStr );
  linfo() << "Accès aux compétences diverses : "
	  << toUtf8StdString( accesStr.data() ) << endmsg;

  for (i = 0; i < NbrClasses; i++)
    {
      infos.push_back( doc.createElement( "Info_Classe" ) );
      infoClasse.appendChild(infos[i]);

      classe.push_back( doc.createElement( "Classe" ) );
      infos[i].appendChild( classe[i] );
      classeStr.push_back( doc.createTextNode( trUtf8(perso ->
						      classePtr(i) ->
						      classe().c_str() ) ) );
      classe[i].appendChild( classeStr[i] );
      linfo() << "Classe : " << toUtf8StdString( classeStr[i].data() )
	      << endmsg;

      QDomElement pv( doc.createElement( "PV" ) );
      infos[i].appendChild( pv );
      QDomText pvStr( doc.createTextNode( QString::number(perso ->
							  classePtr(i) ->
							  pv() ) ) );
      pv.appendChild( pvStr );
      linfo() << "Nombre de pv : " << toUtf8StdString( pvStr.data() ) << endmsg;

      xp.push_back( doc.createElement( "XP" ) );
      infos[i].appendChild( xp[i] );
      xpStr.push_back( doc.createTextNode( QString::number(perso ->
							   classePtr(i) ->
							   xp() ) ) );
      xp[i].appendChild( xpStr[i] );
      linfo() << "XP : " << toUtf8StdString( xpStr[i].data() )
	      << endmsg;

      comp.push_back( doc.createElement( "Competences" ) );
      infos[i].appendChild( comp[i] );
      vecUint = perso -> classePtr(i) -> competences( taille );
      flot.str( "" );
      for_each( vecUint -> begin(), vecUint -> end(), ecrireUInt );
      // vecStr.clear();
      // for (j = 0; j < taille; j++)
      // 	{
      // 	  vecStr.append(  QString::number( (*vecUint)[j] ) );
      // 	  vecStr.append( " " );
      // 	}
      compStr.push_back( doc.createTextNode( trUtf8( flot.str().c_str() ) ) );
      comp[i].appendChild( compStr[i] );
      linfo() << "Compétences de classe : "
	      << toUtf8StdString( compStr[i].data() ) << endmsg;

      sorts.push_back( doc.createElement( "Sorts" ) );
      infos[i].appendChild( sorts[i] );
      vecSorts = perso -> sorts( taille, i );
      if ( taille != 0 )
	{
	  flot.str( "" );
	  for_each( vecSorts -> begin(), vecSorts -> end() , ecrireSort );
	  // vecStr.clear();
	  // for (j = 0; j < taille; j++)
	  // 	{
	  // 	  vecStr.append( QString::number( (*vecSorts)[j].getEcole() ) );
	  // 	  vecStr.append( " " );
	  // 	  vecStr.append( QString::number( (*vecSorts)[j].getNiveau() ) );
	  // 	  vecStr.append( " " );
	  // 	  vecStr.append( QString::number( (*vecSorts)[j].getNumero() ) );
	  // 	  vecStr.append( " " );
	  // 	}
	}
      else
	  flot.str( " " );
      sortsStr.push_back( doc.createTextNode( tr( flot.str().c_str() ) ) );
      sorts[i].appendChild( sortsStr[i] );
      linfo() << "Sorts : " << flot.str() << endmsg;
    }
  
  vecUint = perso -> dons( taille );
  QDomElement dons( doc.createElement( "Dons" ) );
  racine.appendChild( dons );
  flot.str( "" );
  for_each( vecUint -> begin(), vecUint -> end(), ecrireUInt );
  // vecStr.clear();
  // for (i = 0; i < taille; i++)
  //   {
  //     vecStr.append( QString::number( (*vecUint)[i]) );
  //     vecStr.append( " " );
  //   }
  QDomText donsStr( doc.createTextNode( tr( flot.str().c_str() ) ) );
  dons.appendChild( donsStr );
  linfo() << "Dons : " << flot.str() << endmsg;

  vecUint = perso -> desavantages( taille );
  QDomElement desavantages( doc.createElement( "Desavantages" ) );
  racine.appendChild( desavantages );
  // vecStr.clear();
  // for (i = 0; i < taille; i++)
  //   {
  //     vecStr.append( QString::number( (*vecUint)[i]) );
  //     vecStr.append( " " );
  //   }
  flot.str( "" );
  for_each( vecUint -> begin(), vecUint -> end(), ecrireUInt );
  QDomText desavantagesStr( doc.createTextNode( tr( flot.str().c_str() ) ) );
  desavantages.appendChild( desavantagesStr );
  linfo() << "Désavantages : " << flot.str() << endmsg;

  vecUint = perso -> diverses( taille );
  QDomElement diverses( doc.createElement( "Non-martiales" ) );
  racine.appendChild( diverses );
  flot.str( "" );
  for_each( vecUint -> begin(), vecUint -> end(), ecrireUInt ); 
  // vecStr.clear();
  // for (i = 0; i < taille; i++)
  //   {
  //     vecStr.append( QString::number( (*vecUint)[i]) );
  //     vecStr.append( " " );
  //   }
  QDomText diversesStr( doc.createTextNode( tr( flot.str().c_str() ) ) );
  diverses.appendChild( diversesStr );
  linfo() << "Compétences diverses : " << flot.str() << endmsg;

  vecUint = perso -> martiales( taille );
  QDomElement martiales( doc.createElement( "Martiales" ) );
  racine.appendChild( martiales );
  flot.str( "" );
  for_each( vecUint -> begin(), vecUint -> end(), ecrireUInt );  
  // vecStr.clear();
  // for (i = 0; i < taille; i++)
  //   {
  //     vecStr.append( QString::number( (*vecUint)[i]) );
  //     vecStr.append( " " );
  //   }
  QDomText martialesStr( doc.createTextNode( tr( flot.str().c_str() ) ) );
  martiales.appendChild( martialesStr );
  linfo() << "Compétences martiales : " << flot.str() << endmsg;

  func() << "EcrireXML::ecrirePerso -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Permet de modifier le niveau de sortie EcrireXML::interne.
 *
 * @param[in] level nouvelle valeur de EcrireXML::interne.
 */
void EcrireXML::setLevel( const DebugLevelType& level, const unsigned& )
{
  interne = level;
}
